package test;
import java.io.*;
import java.util.*;

import javamoprt.*;

import java.lang.ref.*;

import org.aspectj.lang.*;

class failSafeIteratorCheckMonitor_Set extends javamoprt.MOPSet {
	protected failSafeIteratorCheckMonitor[] elementData;

	public failSafeIteratorCheckMonitor_Set(){
		this.size = 0;
		this.elementData = new failSafeIteratorCheckMonitor[4];
	}

	public final int size(){
		while(size > 0 && elementData[size-1].MOP_terminated) {
			elementData[--size] = null;
		}
		return size;
	}

	public final boolean add(MOPMonitor e){
		ensureCapacity();
		elementData[size++] = (failSafeIteratorCheckMonitor)e;
		return true;
	}

	public final void endObject(int idnum){
		int numAlive = 0;
		for(int i = 0; i < size; i++){
			failSafeIteratorCheckMonitor monitor = elementData[i];
			if(!monitor.MOP_terminated){
				monitor.endObject(idnum);
			}
			if(!monitor.MOP_terminated){
				elementData[numAlive++] = monitor;
			}
		}
		for(int i = numAlive; i < size; i++){
			elementData[i] = null;
		}
		size = numAlive;
	}

	public final boolean alive(){
		for(int i = 0; i < size; i++){
			MOPMonitor monitor = elementData[i];
			if(!monitor.MOP_terminated){
				return true;
			}
		}
		return false;
	}

	public final void endObjectAndClean(int idnum){
		int size = this.size;
		this.size = 0;
		for(int i = size - 1; i >= 0; i--){
			MOPMonitor monitor = elementData[i];
			if(monitor != null && !monitor.MOP_terminated){
				monitor.endObject(idnum);
			}
			elementData[i] = null;
		}
		elementData = null;
	}

	public final void ensureCapacity() {
		int oldCapacity = elementData.length;
		if (size + 1 > oldCapacity) {
			cleanup();
		}
		if (size + 1 > oldCapacity) {
			failSafeIteratorCheckMonitor[] oldData = elementData;
			int newCapacity = (oldCapacity * 3) / 2 + 1;
			if (newCapacity < size + 1){
				newCapacity = size + 1;
			}
			elementData = Arrays.copyOf(oldData, newCapacity);
		}
	}

	public final void cleanup() {
		int numAlive = 0 ;
		for(int i = 0; i < size; i++){
			failSafeIteratorCheckMonitor monitor = (failSafeIteratorCheckMonitor)elementData[i];
			if(!monitor.MOP_terminated){
				elementData[numAlive] = monitor;
				numAlive++;
			}
		}
		for(int i = numAlive; i < size; i++){
			elementData[i] = null;
		}
		size = numAlive;
	}

	public final void event_createColl(Map map, Collection c) {
		int numAlive = 0 ;
		for(int i_1 = 0; i_1 < this.size; i_1++){
			failSafeIteratorCheckMonitor monitor = (failSafeIteratorCheckMonitor)this.elementData[i_1];
			if(!monitor.MOP_terminated){
				elementData[numAlive] = monitor;
				numAlive++;

				monitor.Prop_1_event_createColl(map, c);
				if(monitor.Prop_1_Category_match) {
					monitor.Prop_1_handler_match(map, c, null);
				}
			}
		}
		for(int i_1 = numAlive; i_1 < this.size; i_1++){
			this.elementData[i_1] = null;
		}
		size = numAlive;
	}

	public final void event_createIter(Collection c, Iterator i) {
		int numAlive = 0 ;
		for(int i_1 = 0; i_1 < this.size; i_1++){
			failSafeIteratorCheckMonitor monitor = (failSafeIteratorCheckMonitor)this.elementData[i_1];
			if(!monitor.MOP_terminated){
				elementData[numAlive] = monitor;
				numAlive++;

				monitor.Prop_1_event_createIter(c, i);
				if(monitor.Prop_1_Category_match) {
					monitor.Prop_1_handler_match(null, c, i);
				}
			}
		}
		for(int i_1 = numAlive; i_1 < this.size; i_1++){
			this.elementData[i_1] = null;
		}
		size = numAlive;
	}

	public final void event_useIter(Iterator i) {
		int numAlive = 0 ;
		for(int i_1 = 0; i_1 < this.size; i_1++){
			failSafeIteratorCheckMonitor monitor = (failSafeIteratorCheckMonitor)this.elementData[i_1];
			if(!monitor.MOP_terminated){
				elementData[numAlive] = monitor;
				numAlive++;

				monitor.Prop_1_event_useIter(i);
				if(monitor.Prop_1_Category_match) {
					monitor.Prop_1_handler_match(null, null, i);
				}
			}
		}
		for(int i_1 = numAlive; i_1 < this.size; i_1++){
			this.elementData[i_1] = null;
		}
		size = numAlive;
	}

	public final void event_updateMap(Map map) {
		int numAlive = 0 ;
		for(int i_1 = 0; i_1 < this.size; i_1++){
			failSafeIteratorCheckMonitor monitor = (failSafeIteratorCheckMonitor)this.elementData[i_1];
			if(!monitor.MOP_terminated){
				elementData[numAlive] = monitor;
				numAlive++;

				monitor.Prop_1_event_updateMap(map);
				if(monitor.Prop_1_Category_match) {
					monitor.Prop_1_handler_match(map, null, null);
				}
			}
		}
		for(int i_1 = numAlive; i_1 < this.size; i_1++){
			this.elementData[i_1] = null;
		}
		size = numAlive;
	}

	public final void event_beforeexit() {
		int numAlive = 0 ;
		for(int i_1 = 0; i_1 < this.size; i_1++){
			failSafeIteratorCheckMonitor monitor = (failSafeIteratorCheckMonitor)this.elementData[i_1];
			if(!monitor.MOP_terminated){
				elementData[numAlive] = monitor;
				numAlive++;

				monitor.Prop_1_event_beforeexit();
				if(monitor.Prop_1_Category_match) {
					monitor.Prop_1_handler_match(null, null, null);
				}
			}
		}
		for(int i_1 = numAlive; i_1 < this.size; i_1++){
			this.elementData[i_1] = null;
		}
		size = numAlive;
	}

	public final void event_mainend() {
		int numAlive = 0 ;
		for(int i_1 = 0; i_1 < this.size; i_1++){
			failSafeIteratorCheckMonitor monitor = (failSafeIteratorCheckMonitor)this.elementData[i_1];
			if(!monitor.MOP_terminated){
				elementData[numAlive] = monitor;
				numAlive++;

				monitor.Prop_1_event_mainend();
				if(monitor.Prop_1_Category_match) {
					monitor.Prop_1_handler_match(null, null, null);
				}
			}
		}
		for(int i_1 = numAlive; i_1 < this.size; i_1++){
			this.elementData[i_1] = null;
		}
		size = numAlive;
	}
}

class failSafeIteratorCheckMonitor extends javamoprt.MOPMonitor implements Cloneable, javamoprt.MOPObject {
	public long tau = -1;
	public long modExceptionCount = 0;
	public long monitorStartTime = 0;
	public long exceptionHitTime = 0;
	
	public Object clone() {
		try {
			failSafeIteratorCheckMonitor ret = (failSafeIteratorCheckMonitor) super.clone();
			ret.monitorInfo = (javamoprt.MOPMonitorInfo)this.monitorInfo.clone();
			return ret;
		}
		catch (CloneNotSupportedException e) {
			throw new InternalError(e.toString());
		}
	}

	int Prop_1_state;
	static final int Prop_1_transition_createColl[] = {5, 6, 6, 6, 6, 6, 6};;
	static final int Prop_1_transition_createIter[] = {6, 6, 6, 6, 4, 4, 6};;
	static final int Prop_1_transition_useIter[] = {6, 6, 1, 3, 3, 6, 6};;
	static final int Prop_1_transition_updateMap[] = {6, 6, 2, 2, 2, 5, 6};;
	static final int Prop_1_transition_beforeexit[] = {6, 6, 6, 6, 6, 6, 6};;
	static final int Prop_1_transition_mainend[] = {6, 6, 6, 6, 6, 6, 6};;

	boolean Prop_1_Category_match = false;

	public failSafeIteratorCheckMonitor () {
		Prop_1_state = 0;

	}

	public final void Prop_1_event_createColl(Map map, Collection c) {
		MOP_lastevent = 0;

		Prop_1_state = Prop_1_transition_createColl[Prop_1_state];
		if(this.monitorInfo.isFullParam){
			Prop_1_Category_match = Prop_1_state == 1;
		}
	}

	public final void Prop_1_event_createIter(Collection c, Iterator i) {
		MOP_lastevent = 1;

		Prop_1_state = Prop_1_transition_createIter[Prop_1_state];
		if(this.monitorInfo.isFullParam){
			Prop_1_Category_match = Prop_1_state == 1;
		}
	}

	public final void Prop_1_event_useIter(Iterator i) {
		MOP_lastevent = 2;

		Prop_1_state = Prop_1_transition_useIter[Prop_1_state];
		if(this.monitorInfo.isFullParam){
			Prop_1_Category_match = Prop_1_state == 1;
		}
		monitorStartTime = System.nanoTime();
	}

	public final void Prop_1_event_updateMap(Map map) {
		MOP_lastevent = 3;

		Prop_1_state = Prop_1_transition_updateMap[Prop_1_state];
		if(this.monitorInfo.isFullParam){
			Prop_1_Category_match = Prop_1_state == 1;
		}
	}

	public final void Prop_1_event_beforeexit() {
		MOP_lastevent = 4;

		Prop_1_state = Prop_1_transition_beforeexit[Prop_1_state];
		if(this.monitorInfo.isFullParam){
			Prop_1_Category_match = Prop_1_state == 1;
		}
	}

	public final void Prop_1_event_mainend() {
		MOP_lastevent = 5;

		Prop_1_state = Prop_1_transition_mainend[Prop_1_state];
		if(this.monitorInfo.isFullParam){
			Prop_1_Category_match = Prop_1_state == 1;
		}
	}

	public final void Prop_1_handler_match (Map map, Collection c, Iterator i){
		{
			System.out.println("ConcurrentModification occurred. Tried Iterating while map has been modified.");
			
			failSafeIteratorCheckMonitorAspect.accumulatedModExceptionCount++;
			
			this.exceptionHitTime += (System.nanoTime() - this.monitorStartTime);
			
			failSafeIteratorCheckMonitorAspect.accumulatedModExceptionTime += exceptionHitTime;
		}

	}

	public final void reset() {
		MOP_lastevent = -1;
		Prop_1_state = 0;
		Prop_1_Category_match = false;
	}

	public javamoprt.ref.MOPTagWeakReference MOPRef_map;
	public javamoprt.ref.MOPTagWeakReference MOPRef_c;
	public javamoprt.ref.MOPTagWeakReference MOPRef_i;

	//alive_parameters_0 = [Map map, Collection c, Iterator i]
	public boolean alive_parameters_0 = true;
	//alive_parameters_1 = [Map map, Iterator i]
	public boolean alive_parameters_1 = true;
	//alive_parameters_2 = [Iterator i]
	public boolean alive_parameters_2 = true;

	public final void endObject(int idnum){
		switch(idnum){
			case 0:
			alive_parameters_0 = false;
			alive_parameters_1 = false;
			break;
			case 1:
			alive_parameters_0 = false;
			break;
			case 2:
			alive_parameters_0 = false;
			alive_parameters_1 = false;
			alive_parameters_2 = false;
			break;
		}
		switch(MOP_lastevent) {
			case -1:
			return;
			case 0:
			//createColl
			//alive_map && alive_c && alive_i
			if(!(alive_parameters_0)){
				MOP_terminated = true;
				return;
			}
			break;

			case 1:
			//createIter
			//alive_map && alive_i
			if(!(alive_parameters_1)){
				MOP_terminated = true;
				return;
			}
			break;

			case 2:
			//useIter
			//alive_map && alive_i
			if(!(alive_parameters_1)){
				MOP_terminated = true;
				return;
			}
			break;

			case 3:
			//updateMap
			//alive_i
			if(!(alive_parameters_2)){
				MOP_terminated = true;
				return;
			}
			break;

			case 4:
			//beforeexit
			return;
			case 5:
			//mainend
			return;
		}
		return;
	}

	javamoprt.MOPMonitorInfo monitorInfo;
}

public aspect failSafeIteratorCheckMonitorAspect implements javamoprt.MOPObject {
	/*profiling things */
	
	

	protected long startTime = 0;
	protected long endTime = 0;
	protected static long accumulatedModExceptionTime = 0;
	protected static long accumulatedModExceptionCount = 0;
	protected long accumulatedIterationTime = 0;
	protected long accumulatedIterationCount = 0;
	protected long thisIterationStartTime = 0;
	protected long iteratorCount = 0;
	protected long numIterations = 0;
	protected long mapModCount = 0;
	
	/* Profile stuff ends */
	
	
	javamoprt.map.MOPMapManager failSafeIteratorCheckMapManager;
	public failSafeIteratorCheckMonitorAspect(){
		failSafeIteratorCheckMapManager = new javamoprt.map.MOPMapManager();
		failSafeIteratorCheckMapManager.start();
	}

	// Declarations for the Lock
	static Object failSafeIteratorCheck_MOPLock = new Object();

	// Declarations for Timestamps
	static long failSafeIteratorCheck_timestamp = 1;

	static boolean failSafeIteratorCheck_activated = false;

	// Declarations for Indexing Trees
	static failSafeIteratorCheckMonitor_Set failSafeIteratorCheck_Set = new failSafeIteratorCheckMonitor_Set();
	static failSafeIteratorCheckMonitor failSafeIteratorCheck_Monitor = null;
	static javamoprt.map.MOPAbstractMap failSafeIteratorCheck_map_c_i_Map = new javamoprt.map.MOPMapOfAll(0);
	static javamoprt.ref.MOPTagWeakReference failSafeIteratorCheck_map_c_i_Map_cachekey_0 = javamoprt.map.MOPTagRefMap.NULRef;
	static javamoprt.ref.MOPTagWeakReference failSafeIteratorCheck_map_c_i_Map_cachekey_1 = javamoprt.map.MOPTagRefMap.NULRef;
	static javamoprt.ref.MOPTagWeakReference failSafeIteratorCheck_map_c_i_Map_cachekey_2 = javamoprt.map.MOPTagRefMap.NULRef;
	static failSafeIteratorCheckMonitor failSafeIteratorCheck_map_c_i_Map_cachenode = null;
	static javamoprt.ref.MOPTagWeakReference failSafeIteratorCheck_map_Map_cachekey_0 = javamoprt.map.MOPTagRefMap.NULRef;
	static failSafeIteratorCheckMonitor_Set failSafeIteratorCheck_map_Map_cacheset = null;
	static failSafeIteratorCheckMonitor failSafeIteratorCheck_map_Map_cachenode = null;
	static javamoprt.map.MOPAbstractMap failSafeIteratorCheck_c_i_Map = new javamoprt.map.MOPMapOfAll(1);
	static javamoprt.ref.MOPTagWeakReference failSafeIteratorCheck_c_i_Map_cachekey_1 = javamoprt.map.MOPTagRefMap.NULRef;
	static javamoprt.ref.MOPTagWeakReference failSafeIteratorCheck_c_i_Map_cachekey_2 = javamoprt.map.MOPTagRefMap.NULRef;
	static failSafeIteratorCheckMonitor_Set failSafeIteratorCheck_c_i_Map_cacheset = null;
	static failSafeIteratorCheckMonitor failSafeIteratorCheck_c_i_Map_cachenode = null;
	static javamoprt.ref.MOPTagWeakReference failSafeIteratorCheck_map_c_Map_cachekey_0 = javamoprt.map.MOPTagRefMap.NULRef;
	static javamoprt.ref.MOPTagWeakReference failSafeIteratorCheck_map_c_Map_cachekey_1 = javamoprt.map.MOPTagRefMap.NULRef;
	static failSafeIteratorCheckMonitor_Set failSafeIteratorCheck_map_c_Map_cacheset = null;
	static failSafeIteratorCheckMonitor failSafeIteratorCheck_map_c_Map_cachenode = null;
	static javamoprt.map.MOPAbstractMap failSafeIteratorCheck_i_Map = new javamoprt.map.MOPMapOfSetMon(2);
	static javamoprt.ref.MOPTagWeakReference failSafeIteratorCheck_i_Map_cachekey_2 = javamoprt.map.MOPTagRefMap.NULRef;
	static failSafeIteratorCheckMonitor_Set failSafeIteratorCheck_i_Map_cacheset = null;
	static failSafeIteratorCheckMonitor failSafeIteratorCheck_i_Map_cachenode = null;
	static javamoprt.map.MOPAbstractMap failSafeIteratorCheck_c__To__map_c_Map = new javamoprt.map.MOPMapOfSetMon(1);

	// Trees for References
	static javamoprt.map.MOPRefMap failSafeIteratorCheck_Collection_RefMap = new javamoprt.map.MOPTagRefMap();
	static javamoprt.map.MOPRefMap failSafeIteratorCheck_Iterator_RefMap = new javamoprt.map.MOPTagRefMap();
	static javamoprt.map.MOPRefMap failSafeIteratorCheck_Map_RefMap = new javamoprt.map.MOPTagRefMap();

	pointcut MOP_CommonPointCut() : !within(javamoprt.MOPObject+) && !adviceexecution();
	pointcut failSafeIteratorCheck_createColl(Map map) : ((call(* Map.values()) || call(* Map.keySet())) && target(map)) && MOP_CommonPointCut();
	after (Map map) returning (Collection c) : failSafeIteratorCheck_createColl(map) {
		failSafeIteratorCheck_activated = true;
		synchronized(failSafeIteratorCheck_MOPLock) {
			Object obj;
			javamoprt.map.MOPMap tempMap;
			failSafeIteratorCheckMonitor mainMonitor = null;
			failSafeIteratorCheckMonitor origMonitor = null;
			javamoprt.map.MOPMap mainMap = null;
			failSafeIteratorCheckMonitor_Set mainSet = null;
			failSafeIteratorCheckMonitor_Set monitors = null;
			javamoprt.ref.MOPTagWeakReference TempRef_map;
			javamoprt.ref.MOPTagWeakReference TempRef_c;

			// Cache Retrieval
			if (map == failSafeIteratorCheck_map_c_Map_cachekey_0.get() && c == failSafeIteratorCheck_map_c_Map_cachekey_1.get()) {
				TempRef_map = failSafeIteratorCheck_map_c_Map_cachekey_0;
				TempRef_c = failSafeIteratorCheck_map_c_Map_cachekey_1;

				mainSet = failSafeIteratorCheck_map_c_Map_cacheset;
				mainMonitor = failSafeIteratorCheck_map_c_Map_cachenode;
			} else {
				TempRef_map = failSafeIteratorCheck_Map_RefMap.getTagRef(map);
				TempRef_c = failSafeIteratorCheck_Collection_RefMap.getTagRef(c);
			}

			if (mainSet == null || mainMonitor == null) {
				tempMap = failSafeIteratorCheck_map_c_i_Map;
				obj = tempMap.getMap(TempRef_map);
				if (obj == null) {
					obj = new javamoprt.map.MOPMapOfSetMon(1);
					tempMap.putMap(TempRef_map, obj);
				}
				mainMap = (javamoprt.map.MOPAbstractMap)obj;
				mainMonitor = (failSafeIteratorCheckMonitor)mainMap.getNode(TempRef_c);
				mainSet = (failSafeIteratorCheckMonitor_Set)mainMap.getSet(TempRef_c);
				if (mainSet == null){
					mainSet = new failSafeIteratorCheckMonitor_Set();
					mainMap.putSet(TempRef_c, mainSet);
				}

				if (mainMonitor == null) {
					if (mainMonitor == null) {
						origMonitor = failSafeIteratorCheck_Monitor;
						if (origMonitor != null) {
							boolean timeCheck = true;

							if (TempRef_map.disable > origMonitor.tau) {
								timeCheck = false;
							}
							if (TempRef_c.disable > origMonitor.tau) {
								timeCheck = false;
							}

							if (timeCheck) {
								mainMonitor = (failSafeIteratorCheckMonitor)origMonitor.clone();
								mainMonitor.MOPRef_map = TempRef_map;
								if (TempRef_map.tau == -1){
									TempRef_map.tau = origMonitor.tau;
								}
								mainMonitor.MOPRef_c = TempRef_c;
								if (TempRef_c.tau == -1){
									TempRef_c.tau = origMonitor.tau;
								}
								mainMap.putNode(TempRef_c, mainMonitor);
								mainSet.add(mainMonitor);
								mainMonitor.monitorInfo.isFullParam = false;

								failSafeIteratorCheck_Set.add(mainMonitor);

								tempMap = failSafeIteratorCheck_map_c_i_Map;
								obj = tempMap.getSet(TempRef_map);
								monitors = (failSafeIteratorCheckMonitor_Set)obj;
								if (monitors == null) {
									monitors = new failSafeIteratorCheckMonitor_Set();
									tempMap.putSet(TempRef_map, monitors);
								}
								monitors.add(mainMonitor);

								tempMap = failSafeIteratorCheck_c__To__map_c_Map;
								obj = tempMap.getSet(TempRef_c);
								monitors = (failSafeIteratorCheckMonitor_Set)obj;
								if (monitors == null) {
									monitors = new failSafeIteratorCheckMonitor_Set();
									tempMap.putSet(TempRef_c, monitors);
								}
								monitors.add(mainMonitor);
							}
						}
					}
					if (mainMonitor == null) {
						mainMonitor = new failSafeIteratorCheckMonitor();
						mainMonitor.monitorInfo = new javamoprt.MOPMonitorInfo();
						mainMonitor.monitorInfo.isFullParam = false;

						mainMonitor.MOPRef_map = TempRef_map;
						mainMonitor.MOPRef_c = TempRef_c;

						mainMap.putNode(TempRef_c, mainMonitor);
						mainSet.add(mainMonitor);
						mainMonitor.tau = failSafeIteratorCheck_timestamp;
						if (TempRef_map.tau == -1){
							TempRef_map.tau = failSafeIteratorCheck_timestamp;
						}
						if (TempRef_c.tau == -1){
							TempRef_c.tau = failSafeIteratorCheck_timestamp;
						}
						failSafeIteratorCheck_timestamp++;

						failSafeIteratorCheck_Set.add(mainMonitor);

						tempMap = failSafeIteratorCheck_map_c_i_Map;
						obj = tempMap.getSet(TempRef_map);
						monitors = (failSafeIteratorCheckMonitor_Set)obj;
						if (monitors == null) {
							monitors = new failSafeIteratorCheckMonitor_Set();
							tempMap.putSet(TempRef_map, monitors);
						}
						monitors.add(mainMonitor);

						tempMap = failSafeIteratorCheck_c__To__map_c_Map;
						obj = tempMap.getSet(TempRef_c);
						monitors = (failSafeIteratorCheckMonitor_Set)obj;
						if (monitors == null) {
							monitors = new failSafeIteratorCheckMonitor_Set();
							tempMap.putSet(TempRef_c, monitors);
						}
						monitors.add(mainMonitor);
					}

					TempRef_map.disable = failSafeIteratorCheck_timestamp;
					TempRef_c.disable = failSafeIteratorCheck_timestamp;
					failSafeIteratorCheck_timestamp++;
				}

				failSafeIteratorCheck_map_c_Map_cachekey_0 = TempRef_map;
				failSafeIteratorCheck_map_c_Map_cachekey_1 = TempRef_c;
				failSafeIteratorCheck_map_c_Map_cacheset = mainSet;
				failSafeIteratorCheck_map_c_Map_cachenode = mainMonitor;
			}

			if(mainSet != null) {
				mainSet.event_createColl(map, c);
			}
		}
		/*Profile stuff*/

      	System.out.println("Collection Created!");
      	this.startTime = System.nanoTime();
		
	}

	pointcut failSafeIteratorCheck_createIter(Collection c) : (call(* Collection.iterator()) && target(c)) && MOP_CommonPointCut();
	after (Collection c) returning (Iterator i) : failSafeIteratorCheck_createIter(c) {
		failSafeIteratorCheck_activated = true;
		synchronized(failSafeIteratorCheck_MOPLock) {
			Object obj;
			javamoprt.map.MOPMap tempMap;
			failSafeIteratorCheckMonitor mainMonitor = null;
			failSafeIteratorCheckMonitor origMonitor = null;
			failSafeIteratorCheckMonitor lastMonitor = null;
			javamoprt.map.MOPMap mainMap = null;
			javamoprt.map.MOPMap origMap = null;
			javamoprt.map.MOPMap lastMap = null;
			failSafeIteratorCheckMonitor_Set mainSet = null;
			failSafeIteratorCheckMonitor_Set origSet = null;
			failSafeIteratorCheckMonitor_Set monitors = null;
			javamoprt.ref.MOPTagWeakReference TempRef_map;
			javamoprt.ref.MOPTagWeakReference TempRef_c;
			javamoprt.ref.MOPTagWeakReference TempRef_i;

			// Cache Retrieval
			if (c == failSafeIteratorCheck_c_i_Map_cachekey_1.get() && i == failSafeIteratorCheck_c_i_Map_cachekey_2.get()) {
				TempRef_c = failSafeIteratorCheck_c_i_Map_cachekey_1;
				TempRef_i = failSafeIteratorCheck_c_i_Map_cachekey_2;

				mainSet = failSafeIteratorCheck_c_i_Map_cacheset;
				mainMonitor = failSafeIteratorCheck_c_i_Map_cachenode;
			} else {
				TempRef_c = failSafeIteratorCheck_Collection_RefMap.getTagRef(c);
				TempRef_i = failSafeIteratorCheck_Iterator_RefMap.getTagRef(i);
			}

			if (mainSet == null || mainMonitor == null) {
				tempMap = failSafeIteratorCheck_c_i_Map;
				obj = tempMap.getMap(TempRef_c);
				if (obj == null) {
					obj = new javamoprt.map.MOPMapOfSetMon(2);
					tempMap.putMap(TempRef_c, obj);
				}
				mainMap = (javamoprt.map.MOPAbstractMap)obj;
				mainMonitor = (failSafeIteratorCheckMonitor)mainMap.getNode(TempRef_i);
				mainSet = (failSafeIteratorCheckMonitor_Set)mainMap.getSet(TempRef_i);
				if (mainSet == null){
					mainSet = new failSafeIteratorCheckMonitor_Set();
					mainMap.putSet(TempRef_i, mainSet);
				}

				if (mainMonitor == null) {
					origMap = failSafeIteratorCheck_c__To__map_c_Map;
					origSet = (failSafeIteratorCheckMonitor_Set)origMap.getSet(TempRef_c);
					if (origSet!= null) {
						int numAlive = 0;
						for(int i_1 = 0; i_1 < origSet.size; i_1++) {
							origMonitor = origSet.elementData[i_1];
							Map map = (Map)origMonitor.MOPRef_map.get();
							if (!origMonitor.MOP_terminated && map != null) {
								origSet.elementData[numAlive] = origMonitor;
								numAlive++;

								TempRef_map = origMonitor.MOPRef_map;

								tempMap = failSafeIteratorCheck_map_c_i_Map;
								obj = tempMap.getMap(TempRef_map);
								if (obj == null) {
									obj = new javamoprt.map.MOPMapOfAll(1);
									tempMap.putMap(TempRef_map, obj);
								}
								tempMap = (javamoprt.map.MOPAbstractMap)obj;
								obj = tempMap.getMap(TempRef_c);
								if (obj == null) {
									obj = new javamoprt.map.MOPMapOfMonitor(2);
									tempMap.putMap(TempRef_c, obj);
								}
								lastMap = (javamoprt.map.MOPAbstractMap)obj;
								lastMonitor = (failSafeIteratorCheckMonitor)lastMap.getNode(TempRef_i);
								if (lastMonitor == null) {
									boolean timeCheck = true;

									if (TempRef_i.disable > origMonitor.tau|| (TempRef_i.tau > 0 && TempRef_i.tau < origMonitor.tau)) {
										timeCheck = false;
									}

									if (timeCheck) {
										lastMonitor = (failSafeIteratorCheckMonitor)origMonitor.clone();
										lastMonitor.MOPRef_i = TempRef_i;
										if (TempRef_i.tau == -1){
											TempRef_i.tau = origMonitor.tau;
										}
										lastMap.putNode(TempRef_i, lastMonitor);
										lastMonitor.monitorInfo.isFullParam = true;

										failSafeIteratorCheck_Set.add(lastMonitor);

										tempMap = failSafeIteratorCheck_map_c_i_Map;
										obj = tempMap.getSet(TempRef_map);
										monitors = (failSafeIteratorCheckMonitor_Set)obj;
										if (monitors == null) {
											monitors = new failSafeIteratorCheckMonitor_Set();
											tempMap.putSet(TempRef_map, monitors);
										}
										monitors.add(lastMonitor);

										mainMap = failSafeIteratorCheck_c_i_Map;
										obj = mainMap.getMap(TempRef_c);
										if (obj == null) {
											obj = new javamoprt.map.MOPMapOfSetMon(2);
											mainMap.putMap(TempRef_i, obj);
										}
										mainMap = (javamoprt.map.MOPAbstractMap)obj;
										obj = mainMap.getSet(TempRef_i);
										mainSet = (failSafeIteratorCheckMonitor_Set)obj;
										if (mainSet == null) {
											mainSet = new failSafeIteratorCheckMonitor_Set();
											mainMap.putSet(TempRef_i, mainSet);
										}
										mainSet.add(lastMonitor);

										tempMap = failSafeIteratorCheck_map_c_i_Map;
										obj = tempMap.getMap(TempRef_map);
										if (obj == null) {
											obj = new javamoprt.map.MOPMapOfSetMon(1);
											tempMap.putMap(TempRef_c, obj);
										}
										tempMap = (javamoprt.map.MOPAbstractMap)obj;
										obj = tempMap.getSet(TempRef_c);
										monitors = (failSafeIteratorCheckMonitor_Set)obj;
										if (monitors == null) {
											monitors = new failSafeIteratorCheckMonitor_Set();
											tempMap.putSet(TempRef_c, monitors);
										}
										monitors.add(lastMonitor);

										tempMap = failSafeIteratorCheck_i_Map;
										obj = tempMap.getSet(TempRef_i);
										monitors = (failSafeIteratorCheckMonitor_Set)obj;
										if (monitors == null) {
											monitors = new failSafeIteratorCheckMonitor_Set();
											tempMap.putSet(TempRef_i, monitors);
										}
										monitors.add(lastMonitor);
									}
								}
							}
						}

						for(int i_1 = numAlive; i_1 < origSet.size; i_1++) {
							origSet.elementData[i_1] = null;
						}
						origSet.size = numAlive;
					}
					if (mainMonitor == null) {
						mainMonitor = new failSafeIteratorCheckMonitor();
						mainMonitor.monitorInfo = new javamoprt.MOPMonitorInfo();
						mainMonitor.monitorInfo.isFullParam = false;

						mainMonitor.MOPRef_c = TempRef_c;
						mainMonitor.MOPRef_i = TempRef_i;

						mainMap.putNode(TempRef_i, mainMonitor);
						mainSet.add(mainMonitor);
						mainMonitor.tau = failSafeIteratorCheck_timestamp;
						if (TempRef_c.tau == -1){
							TempRef_c.tau = failSafeIteratorCheck_timestamp;
						}
						if (TempRef_i.tau == -1){
							TempRef_i.tau = failSafeIteratorCheck_timestamp;
						}
						failSafeIteratorCheck_timestamp++;

						failSafeIteratorCheck_Set.add(mainMonitor);

						tempMap = failSafeIteratorCheck_i_Map;
						obj = tempMap.getSet(TempRef_i);
						monitors = (failSafeIteratorCheckMonitor_Set)obj;
						if (monitors == null) {
							monitors = new failSafeIteratorCheckMonitor_Set();
							tempMap.putSet(TempRef_i, monitors);
						}
						monitors.add(mainMonitor);
					}

					TempRef_c.disable = failSafeIteratorCheck_timestamp;
					TempRef_i.disable = failSafeIteratorCheck_timestamp;
					failSafeIteratorCheck_timestamp++;
				}

				failSafeIteratorCheck_c_i_Map_cachekey_1 = TempRef_c;
				failSafeIteratorCheck_c_i_Map_cachekey_2 = TempRef_i;
				failSafeIteratorCheck_c_i_Map_cacheset = mainSet;
				failSafeIteratorCheck_c_i_Map_cachenode = mainMonitor;
			}

			if(mainSet != null) {
				mainSet.event_createIter(c, i);
			}
		}
		
		/*Profiling stuff */
		this.iteratorCount++;
	}

	pointcut failSafeIteratorCheck_useIter(Iterator i) : (call(* Iterator.next()) && target(i)) && MOP_CommonPointCut();
	before (Iterator i) : failSafeIteratorCheck_useIter(i) {
		failSafeIteratorCheck_activated = true;
		synchronized(failSafeIteratorCheck_MOPLock) {
			failSafeIteratorCheckMonitor mainMonitor = null;
			javamoprt.map.MOPMap mainMap = null;
			failSafeIteratorCheckMonitor_Set mainSet = null;
			javamoprt.ref.MOPTagWeakReference TempRef_i;

			// Cache Retrieval
			if (i == failSafeIteratorCheck_i_Map_cachekey_2.get()) {
				TempRef_i = failSafeIteratorCheck_i_Map_cachekey_2;

				mainSet = failSafeIteratorCheck_i_Map_cacheset;
				mainMonitor = failSafeIteratorCheck_i_Map_cachenode;
			} else {
				TempRef_i = failSafeIteratorCheck_Iterator_RefMap.getTagRef(i);
			}

			if (mainSet == null || mainMonitor == null) {
				mainMap = failSafeIteratorCheck_i_Map;
				mainMonitor = (failSafeIteratorCheckMonitor)mainMap.getNode(TempRef_i);
				mainSet = (failSafeIteratorCheckMonitor_Set)mainMap.getSet(TempRef_i);
				if (mainSet == null){
					mainSet = new failSafeIteratorCheckMonitor_Set();
					mainMap.putSet(TempRef_i, mainSet);
				}

				if (mainMonitor == null) {
					mainMonitor = new failSafeIteratorCheckMonitor();
					mainMonitor.monitorInfo = new javamoprt.MOPMonitorInfo();
					mainMonitor.monitorInfo.isFullParam = false;

					mainMonitor.MOPRef_i = TempRef_i;

					failSafeIteratorCheck_i_Map.putNode(TempRef_i, mainMonitor);
					mainSet.add(mainMonitor);
					mainMonitor.tau = failSafeIteratorCheck_timestamp;
					if (TempRef_i.tau == -1){
						TempRef_i.tau = failSafeIteratorCheck_timestamp;
					}
					failSafeIteratorCheck_timestamp++;

					failSafeIteratorCheck_Set.add(mainMonitor);

					TempRef_i.disable = failSafeIteratorCheck_timestamp;
					failSafeIteratorCheck_timestamp++;
				}

				failSafeIteratorCheck_i_Map_cachekey_2 = TempRef_i;
				failSafeIteratorCheck_i_Map_cacheset = mainSet;
				failSafeIteratorCheck_i_Map_cachenode = mainMonitor;
			}

			if(mainSet != null) {
				mainSet.event_useIter(i);
			}
		}
		
		/*Profiling stuff */
		if(this.thisIterationStartTime != 0){
			this.accumulatedIterationTime += (System.nanoTime() - this.thisIterationStartTime);
		}
      	this.accumulatedIterationCount++;
      	this.thisIterationStartTime = System.nanoTime();
	}

	pointcut failSafeIteratorCheck_updateMap(Map map) : ((call(* Map.put*(..)) || call(* Map.putAll*(..)) || call(* Map.clear()) || call(* Map.remove*(..))) && target(map)) && MOP_CommonPointCut();
	after (Map map) : failSafeIteratorCheck_updateMap(map) {
		failSafeIteratorCheck_activated = true;
		synchronized(failSafeIteratorCheck_MOPLock) {
			failSafeIteratorCheckMonitor mainMonitor = null;
			javamoprt.map.MOPMap mainMap = null;
			failSafeIteratorCheckMonitor_Set mainSet = null;
			javamoprt.ref.MOPTagWeakReference TempRef_map;

			// Cache Retrieval
			if (map == failSafeIteratorCheck_map_Map_cachekey_0.get()) {
				TempRef_map = failSafeIteratorCheck_map_Map_cachekey_0;

				mainSet = failSafeIteratorCheck_map_Map_cacheset;
				mainMonitor = failSafeIteratorCheck_map_Map_cachenode;
			} else {
				TempRef_map = failSafeIteratorCheck_Map_RefMap.getTagRef(map);
			}

			if (mainSet == null || mainMonitor == null) {
				mainMap = failSafeIteratorCheck_map_c_i_Map;
				mainMonitor = (failSafeIteratorCheckMonitor)mainMap.getNode(TempRef_map);
				mainSet = (failSafeIteratorCheckMonitor_Set)mainMap.getSet(TempRef_map);
				if (mainSet == null){
					mainSet = new failSafeIteratorCheckMonitor_Set();
					mainMap.putSet(TempRef_map, mainSet);
				}

				if (mainMonitor == null) {
					mainMonitor = new failSafeIteratorCheckMonitor();
					mainMonitor.monitorInfo = new javamoprt.MOPMonitorInfo();
					mainMonitor.monitorInfo.isFullParam = false;

					mainMonitor.MOPRef_map = TempRef_map;

					failSafeIteratorCheck_map_c_i_Map.putNode(TempRef_map, mainMonitor);
					mainSet.add(mainMonitor);
					mainMonitor.tau = failSafeIteratorCheck_timestamp;
					if (TempRef_map.tau == -1){
						TempRef_map.tau = failSafeIteratorCheck_timestamp;
					}
					failSafeIteratorCheck_timestamp++;

					failSafeIteratorCheck_Set.add(mainMonitor);

					TempRef_map.disable = failSafeIteratorCheck_timestamp;
					failSafeIteratorCheck_timestamp++;
				}

				failSafeIteratorCheck_map_Map_cachekey_0 = TempRef_map;
				failSafeIteratorCheck_map_Map_cacheset = mainSet;
				failSafeIteratorCheck_map_Map_cachenode = mainMonitor;
			}

			if(mainSet != null) {
				mainSet.event_updateMap(map);
			}
		}
		
		/* Profiling stuff */
		this.mapModCount++;
		
	}

	pointcut failSafeIteratorCheck_beforeexit() : (call(void System.exit(int))) && MOP_CommonPointCut();
	before () : failSafeIteratorCheck_beforeexit() {
		failSafeIteratorCheck_activated = true;
		synchronized(failSafeIteratorCheck_MOPLock) {
			failSafeIteratorCheckMonitor mainMonitor = null;
			failSafeIteratorCheckMonitor_Set mainSet = null;

			mainSet = failSafeIteratorCheck_Set;
			mainMonitor = failSafeIteratorCheck_Monitor;

			if (mainMonitor == null) {
				mainMonitor = new failSafeIteratorCheckMonitor();
				mainMonitor.monitorInfo = new javamoprt.MOPMonitorInfo();
				mainMonitor.monitorInfo.isFullParam = false;

				failSafeIteratorCheck_Monitor = mainMonitor;
				failSafeIteratorCheck_Set.add(mainMonitor);
				mainMonitor.tau = failSafeIteratorCheck_timestamp;
				failSafeIteratorCheck_timestamp++;
			}

			if(mainSet != null) {
				mainSet.event_beforeexit();
			}
		}
		
		/* Profiling Stuff */
		System.out.println("System.exit called. Printing stats!");
		
		long exceptionhittime = accumulatedModExceptionTime / accumulatedModExceptionCount;
        this.endTime = System.nanoTime();
        System.out.println("-----------------------------------------------------------------------------------------------");
		System.out.println("Total time spent since collection creation:  ---------------- " + (this.endTime - this.startTime) + "ns\t(" + (((this.endTime - this.startTime))/1000000.0) + "ms)");
		System.out.println("Total Iterators used:    ------------------------------------ " + (this.iteratorCount));
		System.out.println("Total Iterations made:   ------------------------------------ " + (this.accumulatedIterationCount));
		System.out.println("Total Map modifications made:   ----------------------------- " + (this.mapModCount));
		System.out.println("Average time per iteration:    ------------------------------ " + (this.accumulatedIterationTime / this.accumulatedIterationCount) + "ns\t(" + (((this.accumulatedIterationTime / this.accumulatedIterationCount))/1000.0) + " micro-seconds)");
		System.out.println("Average time to detect a ConcurrentModificationException:  -- " + (accumulatedModExceptionTime / accumulatedModExceptionCount) + "ns\t(" + (((accumulatedModExceptionTime / accumulatedModExceptionCount))/1000.0) + " micro-seconds)");
		System.out.println("-----------------------------------------------------------------------------------------------");
	}

	pointcut failSafeIteratorCheck_mainend() : (execution(* *.main(..))) && MOP_CommonPointCut();
	after () : failSafeIteratorCheck_mainend() {
		failSafeIteratorCheck_activated = true;
		synchronized(failSafeIteratorCheck_MOPLock) {
			failSafeIteratorCheckMonitor mainMonitor = null;
			failSafeIteratorCheckMonitor_Set mainSet = null;

			mainSet = failSafeIteratorCheck_Set;
			mainMonitor = failSafeIteratorCheck_Monitor;

			if (mainMonitor == null) {
				mainMonitor = new failSafeIteratorCheckMonitor();
				mainMonitor.monitorInfo = new javamoprt.MOPMonitorInfo();
				mainMonitor.monitorInfo.isFullParam = false;

				failSafeIteratorCheck_Monitor = mainMonitor;
				failSafeIteratorCheck_Set.add(mainMonitor);
				mainMonitor.tau = failSafeIteratorCheck_timestamp;
				failSafeIteratorCheck_timestamp++;
			}

			if(mainSet != null) {
				mainSet.event_mainend();
			}
		}
	}

}
